/*
 * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.xuexiang.xgithubclient.adapter;

import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.text.style.TextAppearanceSpan;
import android.view.View;

import androidx.annotation.NonNull;

import com.xuexiang.xaop.annotation.SingleClick;
import com.xuexiang.xgithubclient.R;
import com.xuexiang.xgithubclient.core.http.api.response.event.Event;
import com.xuexiang.xgithubclient.core.http.api.response.event.EventPayload;
import com.xuexiang.xgithubclient.core.http.api.response.event.PushEventCommit;
import com.xuexiang.xgithubclient.util.GitHubHelper;
import com.xuexiang.xgithubclient.util.XToastUtils;
import com.xuexiang.xgithubclient.widget.EllipsizeLineSpan;
import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter;
import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
import com.xuexiang.xui.utils.ResUtils;
import com.xuexiang.xutil.common.StringUtils;
import com.xuexiang.xutil.data.DateUtils;

import java.util.regex.Matcher;

/**
 * 活动列表适配器
 *
 * @author xuexiang
 * @since 2019-08-13 00:00
 */
public class NewsListAdapter extends BaseRecyclerAdapter<Event> implements RecyclerViewHolder.OnViewItemClickListener<Event> {

    @Override
    protected int getItemLayoutId(int viewType) {
        return R.layout.adapter_news_list_item;
    }

    @Override
    protected void bindData(@NonNull RecyclerViewHolder holder, int position, Event item) {
        holder.image(R.id.iv_avatar, item.getActor().getAvatarUrl());
        holder.text(R.id.tv_name, item.getActor().getLogin());
        holder.text(R.id.tv_time, DateUtils.getFuzzyTimeDescriptionByNow(item.getCreatedAt()));

        holder.viewClick(R.id.iv_avatar, this, item, position);
        holder.viewClick(R.id.tv_name, this, item, position);

        setActionAndDesc(holder, item);
    }

    @SingleClick
    @Override
    public void onViewItemClick(View view, Event item, int position) {
        switch (view.getId()) {
            case R.id.iv_avatar:
            case R.id.tv_name:
                XToastUtils.info("点击头像");
                break;
            default:
                break;
        }
    }


    /**
     * 设置动作和描述
     *
     * @param holder
     * @param model
     */
    private void setActionAndDesc(RecyclerViewHolder holder, Event model) {
        String actionStr = null;
        SpannableStringBuilder descSpan = null;
        String fullName = model.getRepo() != null ? model.getRepo().getFullName() : null;
        EventPayload.RefType refType = model.getPayload().getRefType();
        String action = model.getPayload() != null ? model.getPayload().getAction() : null;

        switch (model.getType()) {
            case CommitCommentEvent:
                actionStr = String.format(getString(R.string.created_comment_on_commit), fullName);
                descSpan = new SpannableStringBuilder(model.getPayload().getComment().getBody());
                break;
            case CreateEvent:
                if (EventPayload.RefType.repository.equals(refType)) {
                    actionStr = String.format(getString(R.string.created_repo), fullName);
                } else if (EventPayload.RefType.branch.equals(refType)) {
                    actionStr = String.format(getString(R.string.created_branch_at),
                            model.getPayload().getRef(), fullName);
                } else if (EventPayload.RefType.tag.equals(refType)) {
                    actionStr = String.format(getString(R.string.created_tag_at),
                            model.getPayload().getRef(), fullName);
                }
                break;
            case DeleteEvent:
                if (EventPayload.RefType.branch.equals(refType)) {
                    actionStr = String.format(getString(R.string.delete_branch_at),
                            model.getPayload().getRef(), fullName);
                } else if (EventPayload.RefType.tag.equals(refType)) {
                    actionStr = String.format(getString(R.string.delete_tag_at),
                            model.getPayload().getRef(), fullName);
                }
                break;
            case ForkEvent:
                String oriRepo = model.getRepo().getFullName();
                String newRepo = model.getActor().getLogin() + "/" + model.getRepo().getName();
                actionStr = String.format(getString(R.string.forked_to), oriRepo, newRepo);
                break;
            case GollumEvent:
                actionStr = action + " a wiki page ";
                break;

            case InstallationEvent:
                actionStr = action + " an GitHub App ";
                break;
            case InstallationRepositoriesEvent:
                actionStr = action + " repository from an installation ";
                break;
            case IssueCommentEvent:
                actionStr = String.format(getString(R.string.created_comment_on_issue),
                        model.getPayload().getIssue().getNumber(), model.getRepo().getFullName());
                descSpan = new SpannableStringBuilder(model.getPayload().getComment().getBody());
                break;
            case IssuesEvent:
                String issueEventStr = getIssueEventStr(action);
                actionStr = String.format(issueEventStr,
                        model.getPayload().getIssue().getNumber(), model.getRepo().getFullName());
                descSpan = new SpannableStringBuilder(model.getPayload().getIssue().getTitle());
                break;

            case MarketplacePurchaseEvent:
                actionStr = action + " marketplace plan ";
                break;
            case MemberEvent:
                String memberEventStr = getMemberEventStr(action);
                actionStr = String.format(memberEventStr,
                        model.getPayload().getMember().getLogin(), fullName);
                break;
            case OrgBlockEvent:
                String orgBlockEventStr;
                if (EventPayload.OrgBlockEventActionType.blocked.name().equals(action)) {
                    orgBlockEventStr = getString(R.string.org_blocked_user);
                } else {
                    orgBlockEventStr = getString(R.string.org_unblocked_user);
                }
                actionStr = String.format(orgBlockEventStr,
                        model.getPayload().getOrganization().getLogin(),
                        model.getPayload().getBlockedUser().getLogin());
                break;
            case ProjectCardEvent:
                actionStr = action + " a project ";
                break;
            case ProjectColumnEvent:
                actionStr = action + " a project ";
                break;

            case ProjectEvent:
                actionStr = action + " a project ";
                break;
            case PublicEvent:
                actionStr = String.format(getString(R.string.made_repo_public), fullName);
                break;
            case PullRequestEvent:
                actionStr = action + " pull request " + model.getRepo().getFullName();
                break;
            case PullRequestReviewEvent:
                String pullRequestReviewStr = getPullRequestReviewEventStr(action);
                actionStr = String.format(pullRequestReviewStr, fullName);
                break;
            case PullRequestReviewCommentEvent:
                String pullRequestCommentStr = getPullRequestReviewCommentEventStr(action);
                actionStr = String.format(pullRequestCommentStr, fullName);
                descSpan = new SpannableStringBuilder(model.getPayload().getComment().getBody());
                break;

            case PushEvent:
                String branch = model.getPayload().getBranch();
                actionStr = String.format(getString(R.string.push_to), branch, fullName);

                descSpan = new SpannableStringBuilder("");
                int count = model.getPayload().getCommits().size();
                int maxLines = 4;
                int max = count > maxLines ? maxLines - 1 : count;

                for (int i = 0; i < max; i++) {
                    PushEventCommit commit = model.getPayload().getCommits().get(i);
                    if (i != 0) {
                        descSpan.append("\n");
                    }

                    int lastLength = descSpan.length();
                    String sha = commit.getSha().substring(0, 7);
                    descSpan.append(sha);
                    descSpan.setSpan(new TextAppearanceSpan(holder.itemView.getContext(), R.style.text_link),
                            lastLength, lastLength + sha.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

                    descSpan.append(" ");
                    descSpan.append(getFirstLine(commit.getMessage()));

                    descSpan.setSpan(new EllipsizeLineSpan(i == (count - 1) ? 0 : 0),
                            lastLength, descSpan.length(), 0);
                }
                if (count > maxLines) {
                    descSpan.append("\n").append("...");
                }
                break;
            case ReleaseEvent:
                actionStr = String.format(getString(R.string.published_release_at),
                        model.getPayload().getRelease().getTagName(), fullName);
                break;
            case WatchEvent:
                actionStr = String.format(getString(R.string.starred_repo), fullName);
                break;
            default:
                break;
        }

        holder.visible(R.id.action, View.VISIBLE);
        if (descSpan != null) {
            holder.visible(R.id.desc, View.VISIBLE);
            holder.text(R.id.desc, descSpan);
        } else {
            holder.visible(R.id.desc, View.GONE);
        }

        actionStr = StringUtils.upperFirstLetter(actionStr);
        actionStr = actionStr == null ? "" : actionStr;
        SpannableStringBuilder span = new SpannableStringBuilder(actionStr);
        Matcher matcher = GitHubHelper.REPO_FULL_NAME_PATTERN.matcher(actionStr);
        for (; matcher.find(); ) {
            span.setSpan(new StyleSpan(Typeface.BOLD), matcher.start(), matcher.end(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        holder.text(R.id.action, span);
    }

    private String getFirstLine(String str) {
        if (str == null || !str.contains("\n")) {
            return str;
        }
        return str.substring(0, str.indexOf("\n"));
    }

    private String getPullRequestReviewEventStr(String action) {
        EventPayload.PullRequestReviewEventActionType actionType =
                EventPayload.PullRequestReviewEventActionType.valueOf(action);
        switch (actionType) {
            case submitted:
                return getString(R.string.submitted_pull_request_review_at);
            case edited:
                return getString(R.string.edited_pull_request_review_at);
            case dismissed:
                return getString(R.string.dismissed_pull_request_review_at);
            default:
                return getString(R.string.submitted_pull_request_review_at);
        }
    }

    private String getPullRequestReviewCommentEventStr(String action) {
        EventPayload.PullRequestReviewCommentEventActionType actionType =
                EventPayload.PullRequestReviewCommentEventActionType.valueOf(action);
        switch (actionType) {
            case created:
                return getString(R.string.created_pull_request_comment_at);
            case edited:
                return getString(R.string.edited_pull_request_comment_at);
            case deleted:
                return getString(R.string.deleted_pull_request_comment_at);
            default:
                return getString(R.string.created_pull_request_comment_at);
        }
    }

    private String getMemberEventStr(String action) {
        EventPayload.MemberEventActionType actionType = EventPayload.MemberEventActionType.valueOf(action);
        switch (actionType) {
            case added:
                return getString(R.string.added_member_to);
            case deleted:
                return getString(R.string.deleted_member_at);
            case edited:
                return getString(R.string.edited_member_at);
            default:
                return getString(R.string.added_member_to);
        }
    }

    private String getIssueEventStr(String action) {
        EventPayload.IssueEventActionType actionType = EventPayload.IssueEventActionType.valueOf(action);
        switch (actionType) {
            case assigned:
                return getString(R.string.assigned_issue_at);
            case unassigned:
                return getString(R.string.unassigned_issue_at);
            case labeled:
                return getString(R.string.labeled_issue_at);
            case unlabeled:
                return getString(R.string.unlabeled_issue_at);
            case opened:
                return getString(R.string.opened_issue_at);

            case edited:
                return getString(R.string.edited_issue_at);
            case milestoned:
                return getString(R.string.milestoned_issue_at);
            case demilestoned:
                return getString(R.string.demilestoned_issue_at);
            case closed:
                return getString(R.string.closed_issue_at);
            case reopened:
                return getString(R.string.reopened_issue_at);

            default:
                return getString(R.string.opened_issue_at);
        }
    }

    private String getString(int resId) {
        return ResUtils.getString(resId);
    }
}
